﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.IO;

namespace Client
{
    class AssemblyManager
    {
        protected Dictionary<int, Assembly> _assemblyCache;

        protected List<int> _assemblyStored;

        protected string _path = @"Datastore\Projects";

        public AssemblyManager()
        {
            _path = Path.Combine(Environment.CurrentDirectory, _path);
            this._assemblyStored = Directory
                .EnumerateDirectories(_path)
                .Select(p => int.Parse(Path.GetFileName(p)))
                .ToList();
            this._assemblyCache = new Dictionary<int, Assembly>();
            this.Clean();
        }

        public Type GetType(int projectId)
        {
            Assembly assembly;
            if(_assemblyCache.Any(a => a.Key == projectId)){
                assembly = _assemblyCache[projectId];
            } else if(_assemblyStored.Any(a => a.Equals(projectId))){
                assembly = LoadAssembly(projectId);
            } else {
                DownloadProject(projectId);
                assembly = LoadAssembly(projectId);
            }

           Type type = assembly.GetType("Lib.Controller");

           this.Clean();

           return type;
        }

        private Assembly LoadAssembly(int projectId)
        {
            Assembly assembly = Assembly
                .LoadFrom(Path.Combine(_path, projectId.ToString(), "Client.dll"));
            _assemblyCache.Add(projectId, assembly);
            _assemblyStored.Add(projectId);
            return assembly;
        }

        private void DownloadProject(int projectId)
        {
            var files = ServerConnection.Instance.GetProjectFiles(projectId);
            DirectoryInfo di = Directory.CreateDirectory(Path.Combine(_path, projectId.ToString()));
            foreach(var file in files){
                using (FileStream fs = File.Create(Path.Combine(di.FullName,file.Path)))
                {
                    fs.Write(file.File, 0, file.File.Length);
                }
            }
        }

        protected void Clean()
        {
           var projects = ServerConnection.Instance.GetActiveProjects();
           List<int> projectsToRemove = new List<int>();
           foreach (int projectId in _assemblyStored)
           {
               if(!projects.Any(p => p.ProjectId == projectId)){
                   projectsToRemove.Add(projectId);
               }
           }

            foreach(int projectId in projectsToRemove){
                RemoveProject(projectId);
            }
        }

        private void RemoveProject(int projectId){
            _assemblyStored.Remove(projectId);
            _assemblyCache.Remove(projectId);
            System.IO.DirectoryInfo directory = new System.IO.DirectoryInfo(Path.Combine(_path, projectId.ToString()));
            foreach (System.IO.FileInfo file in directory.GetFiles()) file.Delete();
            foreach (System.IO.DirectoryInfo subDirectory in directory.GetDirectories()) subDirectory.Delete(true);
        }
    }
}
